package ctrutil

import (
	"sync"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"fmt"
	"strings"
	"cloud_worm/util/uhttp"
	"io/ioutil"
	"encoding/json"
	"cloud_worm/util/proto/ujson"
)

// ResourceServers 资源服务器
type ResourceServers struct {
	Address 		[]string
	UploadFileURLs 	[]string
}

type DataUrl struct {
	Url string      `json:"url"`
}

type ResponseData struct {
	Code int            `json:"code"`
	Msg  string         `json:"msg"`
	Data DataUrl        `json:"data"`
}

// UploadFile 向resource server上传文件
func (r *ResourceServers) UploadFile(fileName string, uploadURL string) (string, error) {

	var fileUrl string
	for _, item := range r.UploadFileURLs {
		// 上传文件
		response, err := uhttp.PostFile(fileName, item + uploadURL)
		if err != nil {
			msg := fmt.Sprintf("upload file to '%s' failed: %s", item + uploadURL, err.Error())
			logs.Error(msg)
			return "", fmt.Errorf(msg)
		}

		// 解析内容
		content, err := ioutil.ReadAll(response.Body)
		if err != nil {
			msg := fmt.Sprintf("upload file to '%s' failed: %s", item + uploadURL, err.Error())
			logs.Error(msg)
			return "", fmt.Errorf(msg)
		}

		// json格式解析
		var result ResponseData
		err = json.Unmarshal(content, &result)
		if err != nil {
			msg := fmt.Sprintf("upload file to '%s' failed: %s", item + uploadURL, err.Error())
			logs.Error(msg)
			return "", fmt.Errorf(msg)
		}
		if result.Code != uhttp.RespCodeOk || len(result.Data.Url) <= 0 {
			msg := fmt.Sprintf("upload file to '%s' failed: %s", item + uploadURL, result.Msg)
			logs.Error(msg)
			return "", fmt.Errorf(msg)
		}

		// 匹配一致的结果
		if len(fileUrl) == 0 {
			fileUrl = result.Data.Url
			continue
		}

		if fileUrl != result.Data.Url {
			msg := fmt.Sprintf("upload file '%s' url: %s diff with %s", item + uploadURL, result.Data.Url, fileUrl)
			logs.Error(msg)
			return "", fmt.Errorf(msg)
		}
		logs.Debug("upload file over: %s, %s", fileName, item + uploadURL)
	}

	if len(fileUrl) == 0 {
		return "", fmt.Errorf("'%s' no upload for '%s'", fileName, uploadURL)
	}
	return fileUrl, nil
}

func (r *ResourceServers) PostGrayConfig(ip string, config ujson.GrayConfig) error {
	for _, item := range r.UploadFileURLs {
		if strings.Contains(item, ip) == false {
			continue
		}

		postURL := fmt.Sprintf("%s/gray/router/set", item)
		logs.Debug(postURL)
		resp, err := uhttp.HttpsPostJSON(postURL, config)
		if err != nil {
			return fmt.Errorf("post '%s' error: %s", postURL, err.Error())
		}
		respJson := new(uhttp.ResponData)
		if err = json.Unmarshal(resp, respJson); err != nil {
			return fmt.Errorf("post '%s' error: %s", postURL, err.Error())
		}

		if respJson.Code != uhttp.RespCodeOk {
			return fmt.Errorf("post '%s' error: %s", postURL, respJson.Data)
		}

		break
	}

	return nil
}

func (r *ResourceServers) GetGrayConfig() ([]*ujson.GrayConfig, error) {
	var result []*ujson.GrayConfig

	for _, item := range r.UploadFileURLs {
		getURL := fmt.Sprintf("%s/gray/router/get", item)
		logs.Debug(getURL)
		body := uhttp.HttpsGet(getURL)
		if body == "" {
			return nil, fmt.Errorf("get gray config from '%s' error", getURL)
		}

		respJson := new(uhttp.ResponData)
		if err := json.Unmarshal([]byte(body), respJson); err != nil {
			return nil, fmt.Errorf("get gray config from '%s' error: %s", getURL, err.Error())
		}

		c := new(ujson.GrayConfig)
		if err := uhttp.MapDecode(respJson.Data, c); err != nil {
			return nil, fmt.Errorf("get gray config from '%s' error: %s", getURL, err.Error())
		}

		result = append(result, c)
	}

	return result, nil
}

// ResourceSet 返回资源服务器集合的对象
func ResourceSet() *ResourceServers {
	return resourceServer
}

var resourceServer *ResourceServers
var resourceOnce sync.Once

// init 初始化加载resource server
func init()  {
	resourceOnce.Do(func() {
		resourceServer = new(ResourceServers)
	})

	tmp := ResourceSet()
	if tmp == nil {
		panic("create resource_server set failed")
	}

	var servers []string
	res := beego.AppConfig.String(fmt.Sprintf("%s::server.resource", RunMode))
	tmps := strings.Split(res, ",")
	for _, item := range tmps {
		item = strings.TrimSpace(item)
		if len(item) <= 0 {
			continue
		}
		if len(strings.Split(item, ":")) != 2 && len(strings.Split(item, ":")) != 3 {
			continue
		}
		servers = append(servers, item)
	}
	logs.Info(fmt.Sprintf("resource config: %s", res))

	for i, item := range servers {
		var uploadFileURL string
		if strings.HasPrefix(item, "http") {
			uploadFileURL = item
		} else {
			uploadFileURL = fmt.Sprintf("https://%s", item)			// 缺省采用https的方式
		}
		logs.Info(fmt.Sprintf("resource server: %d, %s, %s", i, item, uploadFileURL))
		ResourceSet().Address = append(ResourceSet().Address, item)
		ResourceSet().UploadFileURLs = append(ResourceSet().UploadFileURLs, uploadFileURL)
	}

	if len(ResourceSet().UploadFileURLs) == 0 {
		panic("no resource server")
	}
	return
}